#include "leafsegmentation.h"
#include "leafcurvature.h"
#include "leafdatabase.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <QDir>
#include <iostream>
#include <fstream>
#include <cstdlib>

#include <pthread.h>

using namespace cv;
using namespace std;

#define NUM_THREADS     4

typedef struct{
    string name;
    vector<string> match_names;
    int rank;
} Result;

std::vector<Result> results;
LeafDatabase* database=0;

void *PrintHello(void *threadid)
{
   unsigned long tid;
   tid = (unsigned long)threadid;
   unsigned int stride=results.size()/NUM_THREADS+1;
   unsigned int start=tid*stride;
   unsigned int end=std::min((tid+1)*stride,results.size());
   std::cout<<start<<" "<<end<<std::flush;
   for(unsigned int i=start;i<end;i++)
   {
       int sample_id=i;//rand()%database->features.size();
       LeafDatabase::Entry& query_entry=database->features[sample_id];
       std::vector<LeafDatabase::Entry*> closestEntries=database->closestNEntries(sample_id);
       results[i].name=query_entry.name;
       bool found=false;
       for(unsigned eid=0;eid<closestEntries.size();eid++)
       {
           results[i].match_names.push_back(closestEntries[eid]->name);
           if(!found&&query_entry.name.compare(closestEntries[eid]->name)==0)
           {
               results[i].rank=eid+1;
               found=true;
           }
       }
       if(!found)results[i].rank=30;
   }
   pthread_exit(NULL);
}

int main(int, char**)
{
    database=LeafDatabase::GetInstance();
    unsigned int number_of_sample=database->features.size();

    results.resize(number_of_sample);

    pthread_t threads[NUM_THREADS];
    pthread_attr_t attr;
    int rc;
    long t;
    void *status;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    for(t=0; t<NUM_THREADS; t++){
       printf("In main: creating thread %ld\n", t);
       rc = pthread_create(&threads[t], &attr, PrintHello, (void *)t);
       if (rc){
          printf("ERROR; return code from pthread_create() is %d\n", rc);
          exit(-1);
       }
    }

    pthread_attr_destroy(&attr);
    for(t=0; t<NUM_THREADS; t++) {
        rc = pthread_join(threads[t], &status);
        if (rc) {
            printf("ERROR; return code from pthread_join() is %d\n", rc);
            exit(-1);
        }
        printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
    }

    ofstream result_file("result.csv");

    for(unsigned int i=0;i<number_of_sample;i++)
    {
        result_file<<results[i].name<<","<<results[i].rank;
        for(unsigned j=0;j<results[i].match_names.size();j++)
        {
            result_file<<","<<results[i].match_names[j];
        }
        result_file<<std::endl;
    }
    result_file.close();

    return 0;
}
